/**
 * 常用公共方法
 */
import _ from 'lodash'

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
	if (('' + time).length === 10) {
		time = parseInt(time) * 1000
	} else {
		time = +time
	}
	const d = new Date(time)
	const now = Date.now()

	const diff = (now - d) / 1000

	if (diff < 30) {
		return '刚刚'
	} else if (diff < 3600) {
		// less 1 hour
		return Math.ceil(diff / 60) + '分钟前'
	} else if (diff < 3600 * 24) {
		return Math.ceil(diff / 3600) + '小时前'
	} else if (diff < 3600 * 24 * 2) {
		return '1天前'
	}
	if (option) {
		return parseTime(time, option)
	} else {
		return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
	}
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
	// returns the byte length of an utf8 string
	let s = str.length
	for (var i = str.length - 1; i >= 0; i--) {
		const code = str.charCodeAt(i)
		if (code > 0x7f && code <= 0x7ff) {
			s++
		} else if (code > 0x7ff && code <= 0xffff) {
			s += 2
		}
		if (code >= 0xdc00 && code <= 0xdfff) {
			i--
		}
	}
	return s
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
	const newArray = []
	for (let i = 0; i < actual.length; i++) {
		if (actual[i]) {
			newArray.push(actual[i])
		}
	}
	return newArray
}

/**
 * url参数转对象
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
	const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
	if (!search) {
		return {}
	}
	const obj = {}
	const searchArr = search.split('&')
	searchArr.forEach((v) => {
		const index = v.indexOf('=')
		if (index !== -1) {
			const name = v.substring(0, index)
			const val = v.substring(index + 1, v.length)
			obj[name] = val
		}
	})
	return obj
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
	const div = document.createElement('div')
	div.innerHTML = val
	return div.textContent || div.innerText
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
	if (typeof target !== 'object') {
		target = {}
	}
	if (Array.isArray(source)) {
		return source.slice()
	}
	Object.keys(source).forEach((property) => {
		const sourceProperty = source[property]
		if (typeof sourceProperty === 'object') {
			target[property] = objectMerge(target[property], sourceProperty)
		} else {
			target[property] = sourceProperty
		}
	})
	return target
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
	if (!element || !className) {
		return
	}
	let classString = element.className
	const nameIndex = classString.indexOf(className)
	if (nameIndex === -1) {
		classString += '' + className
	} else {
		classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
	}
	element.className = classString
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate = false) {
	let timeout, args, context, timestamp, result

	const later = function () {
		// 据上一次触发时间间隔
		const last = +new Date() - timestamp

		// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
		if (last < wait && last > 0) {
			timeout = setTimeout(later, wait - last)
		} else {
			timeout = null
			// 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
			if (!immediate) {
				result = func.apply(context, args)
				if (!timeout) {
					context = args = null
				}
			}
		}
	}

	return function (...args) {
		context = this
		timestamp = +new Date()
		const callNow = immediate && !timeout
		// 如果延时不存在，重新设定延时
		if (!timeout) {
			timeout = setTimeout(later, wait)
		}
		if (callNow) {
			result = func.apply(context, args)
			context = args = null
		}

		return result
	}
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
	if (!source && typeof source !== 'object') {
		throw new Error('error arguments', 'deepClone')
	}
	const targetObj = source.constructor === Array ? [] : {}
	Object.keys(source).forEach((keys) => {
		if (source[keys] && typeof source[keys] === 'object') {
			targetObj[keys] = deepClone(source[keys])
		} else {
			targetObj[keys] = source[keys]
		}
	})
	return targetObj
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
	return Array.from(new Set(arr))
}

/**
 * 判断变量类型
 * @param v
 * @returns {string}
 */
export function myTypeof(v) {
	let str = Object.prototype.toString.call(v)
	return str.replace(/\[object |]/g, '')
}

/**
 * 判断一个值是否为有效值，有效值：不为空即为有效
 * @param val 需要判断的值
 * @returns {boolean}
 */
export function isValidVal(val) {
	return val !== undefined && val !== null && val !== ''
}

/**
 * 去掉对象属性前后空格
 */
export function trimObj(obj) {
	let p = myTypeof(obj)
	if (p === 'Object') {
		for (let key in obj) {
			if (obj.hasOwnProperty(key)) {
				let o = myTypeof(obj[key])
				if (o === 'String') {
					obj[key] = obj[key].trim()
				} else if (o === 'Object' || o === 'Array') {
					trimObj(obj[key])
				}
			}
		}
	} else if (p === 'Array') {
		for (let i = 0, l = obj.length; i < l; i++) {
			let t = myTypeof(obj[i])
			if (t === 'String') {
				obj[i] = obj[i].trim()
			} else if (t === 'Array' || t === 'Object') {
				trimObj(obj[i])
			}
		}
	}
	return obj
}

/**
 * 按条件查找一个元素在集合中的位置（路径），返回找到的第一个符合条件的位置
 * 仅适用于[{children:[{...},...],...},...]类似树结构集合（最外层也可以是一个对象）或一维数组
 * @param {Array/Object} group - 集合，被查找的集合，必填
 * @param {Function/String/Number/Boolean} condition - 查找条件，为常量时，将常量和集合元素直接对比，必填
 * @param {String} pathKey - 查找结果（路径）元素在集合中的key，在集合为数组时，可以不填，返回index（索引）
 * @param {String} childKey - 集合子元素的key，默认值'children'
 * @param {Array} path - 递归用参数，逻辑内部参数，不用传
 * @return {Array} 返回带有路径（层级）信息的数组
 * @example group: {id:1,name:'爸爸',children:[{id:2,name:'大儿子'},{id:3,name:'二儿子'}]}
 *          condition: e=>e.id === 3
 *          pathKey: 'name'
 *          childKey: 'children'
 *
 *          返回：['爸爸','二儿子']
 */
export function findPath({ group, condition, pathKey, childKey = 'children', path = [] }) {
	if (group && _.isObject(group)) {
		if (_.isFunction(condition)) {
			if (_.isPlainObject(group)) {
				let item = group
				let temp = _.cloneDeep(path)
				if (condition(item)) {
					if (pathKey && item[pathKey]) {
						temp.push(item[pathKey])
					}
					return temp
				} else if (item[childKey] && !_.isEmpty(item[childKey])) {
					if (pathKey && item[pathKey]) {
						temp.push(item[pathKey])
					}
					let rr = findPath({
						group: item[childKey],
						condition: condition,
						pathKey: pathKey,
						childKey: childKey,
						path: temp
					})
					if (!_.isEmpty(rr)) {
						return rr
					}
				}
			} else if (Array.isArray(group)) {
				for (let item of group) {
					let temp = _.cloneDeep(path)
					if (condition(item)) {
						if (pathKey && item[pathKey]) {
							temp.push(item[pathKey])
						} else {
							temp.push(group.indexOf(item))
						}
						return temp
					} else if (item[childKey] && item[childKey].length > 0) {
						if (pathKey && item[pathKey]) {
							temp.push(item[pathKey])
						} else {
							temp.push(group.indexOf(item))
						}
						let rr = findPath({
							group: item[childKey],
							condition: condition,
							pathKey: pathKey,
							childKey: childKey,
							path: temp
						})
						if (!_.isEmpty(rr)) {
							return rr
						}
					}
				}
			}
		} else if (Array.isArray(group)) {
			//条件为常量，集合为数组，这种情况只会有一种业务场景：在一维数组中查找某个常量在数组中第一次出现的index
			for (let item of group) {
				let temp = _.cloneDeep(path)
				if (item === condition) {
					temp.push(group.indexOf(item))
					return temp
				}
			}
		}
	}
	return []
}

/**
 * 图片拼接
 */
export function imageSplicing(path) {
  if (path && path.indexOf('http') < 0) {
    return (window.global && window.global.serverImg + path) || path
	} else {
		return path || ''
	}
}
